/**
 *  \file monAirportRhapsodyPo.c (implementation file)
 *
 *  \brief Problem name: Airport rhapsody.
 *
 *  \brief Concept: António Rui Borges
 *
 *  Synchronization based on monitors.
 *  Both threads and the monitor are implemented using the pthread library which enables the creation of a
 *  monitor of the Lampson / Redell type.
 *
 *  Definition of the operations carried out by the porter thread:
 *     \li take a rest
 *     \li try to collect a bag
 *     \li carry it to the appropriate store
 *     \li no more bags to collect.
 *
 *  \author António Rui Borges - December 2013
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#include <errno.h>

#include "probConst.h"
#include "probDataStruct.h"
#include "cam.h"
#include "logging.h"
#include "monAirportRhapsodyIDS.h"

/** \brief logging file name */
extern char nFic[51];

/** \brief porter thread return status */
extern int statusPO;

/**
 *  \brief Take a rest.
 *
 *  The porter reads the newspaper while waiting for next assignment.
 *  He waits while not all the N passengers have left the plane which has just landed. He proceeds otherwise.
 *
 *  No state should be saved.
 *
 *  \param k plane landing number
 */

void takeARest (unsigned int k)
{
  if ((statusPO = pthread_mutex_lock (&accessCR)) != 0)                                             /* enter monitor */
     { errno = statusPO;                                                                      /* save error in errno */
       perror ("error on entering the monitor (PO)");
       statusPO = EXIT_FAILURE;
       pthread_exit (&statusPO);
     }
  pthread_once (&init, initialization);                                              /* internal data initialization */

    //temos de esperar que o aviao aterre


    /* insert youy code here */
    //aqui vamos fazer um wait para bloquear
    //wait(aviao aterrar);
    // tem de ser o bagageiro a dar reset do numero de passangeiros que ja sairam do aviao(neste caso max), nao me lembro da letra 

  while(nPassP < N)
  {
	pthread_cond_wait(&waitingFlight,&accessCR);
  }

  nPassP -= N;
  
  if ((statusPO = pthread_mutex_unlock (&accessCR)) != 0)                                            /* exit monitor */
     { errno = statusPO;                                                                      /* save error in errno */
       perror ("error on exiting monitor (PO)");
       statusPO = EXIT_FAILURE;
       pthread_exit (&statusPO);
     }
}

/**
 *  \brief Try to collect a bag.
 *
 *  The porter goes to the plane's hold and checks if there are bags still left to be collected. If so, he picks up one
 *  and leaves. If not, and before leaving, he informs the passengers who may be still waiting that there are no more
 *  bags left.
 *
 *  State should be saved.
 *
 *  \param k plane landing number
 *  \param p_bag pointer to the location where the retrieved bag should be stored
 *
 *  \return \c true, if he has picked up a bag
 *  \return \c false, otherwise
 */

bool tryToCollectABag (unsigned int k, BAG *p_bag)
{
  if ((statusPO = pthread_mutex_lock (&accessCR)) != 0)                                             /* enter monitor */
     { errno = statusPO;                                                                      /* save error in errno */
       perror ("error on entering the monitor (PO)");
       statusPO = EXIT_FAILURE;
       pthread_exit (&statusPO);
     }
  pthread_once (&init, initialization);                                              /* internal data initialization */

	bool pickedABag;

     //Ainda existem malas?
     
     if(fSt.plHold[k].nBags != 0)
     {
		fSt.plHold[k].nBags--;
		*p_bag = fSt.plHold[k].bag[fSt.plHold[k].nBags];
		pickedABag = true;
	 }
	 else
	 {
		 unsigned int i;
		 for( i = 0; i < N; i++)
		 {
			 if(fSt.st.passStat[k][i].stat==AT_THE_LUGGAGE_COLLECTION_POINT &&
			    ((fSt.st.passStat[k][i].nBagsAct+nCalls[i]) != fSt.st.passStat[k][i].nBagsReal))
			 {
				pthread_cond_signal(&pass[i]); 
				nCalls[i]++;
			 }
		 }
		 pickedABag = false;
	 }

	fSt.st.porterStat = AT_THE_PLANES_HOLD;
	saveState(nFic, k, &fSt);
             
  if ((statusPO = pthread_mutex_unlock (&accessCR)) != 0)                                            /* exit monitor */
     { errno = statusPO;                                                                      /* save error in errno */
       perror ("error on exiting monitor (PO)");
       statusPO = EXIT_FAILURE;
       pthread_exit (&statusPO);
     }

	return pickedABag;
}

/**
 *  \brief Carry it to the appropriate store.
 *
 *  The porter checks the bag identification. If it is unknown, he issues an error message.
 *
 *  He then checks the passenger flight situation. If she has this airport as her final destination, he deposits the
 *  bag on the belt conveyor and informs the passenger. Otherwise, he takes the bag to the storeroom for temporary
 *  storage. He also updates statistical data in both cases.
 *
 *  State should be saved.
 *
 *  \param k plane landing number
 *  \param p_bag pointer to the location where the retrieved bag should be stored
 */

void carryItToAppropriateStore (unsigned int k, BAG *p_bag)
{
  if ((statusPO = pthread_mutex_lock (&accessCR)) != 0)                                             /* enter monitor */
     { errno = statusPO;                                                                      /* save error in errno */
       perror ("error on entering the monitor (PO)");
       statusPO = EXIT_FAILURE;
       pthread_exit (&statusPO);
     }
  pthread_once (&init, initialization);                                              /* internal data initialization */

	if(p_bag->id >= N)
	{
		fprintf(stderr, "error on bag identification\n");
        statusPO = EXIT_FAILURE;
        pthread_exit (&statusPO);

	}
	else 
	{
		if(fSt.st.passStat[k][p_bag->id].sit == FD)    // Final Destination?
		{
			camIn(&(fSt.convBelt),p_bag->id);
			fSt.nToTBagsPCB++;
			fSt.st.porterStat = AT_THE_LUGGAGE_BELT_CONVEYOR;
			nCalls[p_bag->id]++;
			pthread_cond_signal(&pass[p_bag->id]);
			
		}
		else if(fSt.st.passStat[k][p_bag->id].sit == TRT)  // In transit?
		{
			fSt.nToTBagsPSR++;
			fSt.st.porterStat = AT_THE_STOREROOM;
			fSt.st.passStat[k][p_bag->id].nBagsAct++;
		}
	}
	
	saveState(nFic, k, &fSt);
	
            


  if ((statusPO = pthread_mutex_unlock (&accessCR)) != 0)                                            /* exit monitor */
     { errno = statusPO;                                                                      /* save error in errno */
       perror ("error on exiting monitor (PO)");
       statusPO = EXIT_FAILURE;
       pthread_exit (&statusPO);
     }
}

/**
 *  \brief No more bags to collect.
 *
 *  The porter goes back to his office.
 *
 *  State should be saved.
 *
 *  \param k plane landing number
 */

void noMoreBagsToCollect (unsigned int k)
{
  if ((statusPO = pthread_mutex_lock (&accessCR)) != 0)                                             /* enter monitor */
     { errno = statusPO;                                                                      /* save error in errno */
       perror ("error on entering the monitor (PO)");
       statusPO = EXIT_FAILURE;
       pthread_exit (&statusPO);
     }
  pthread_once (&init, initialization);                                              /* internal data initialization */

	fSt.st.porterStat = WAITING_FOR_A_PLANE_TO_LAND;
	saveState(nFic, k, &fSt);


  if ((statusPO = pthread_mutex_unlock (&accessCR)) != 0)                                            /* exit monitor */
     { errno = statusPO;                                                                      /* save error in errno */
       perror ("error on exiting monitor (PO)");
       statusPO = EXIT_FAILURE;
       pthread_exit (&statusPO);
     }
}
